import cv2
import mediapipe as mp
import time
import math

class HandDetector():
    def __init__(self,static_image_mode=False,max_num_hands=2,model_complexity=1,min_detection_confidence=0.5,
               min_tracking_confidence=0.5):

        self.mode = static_image_mode
        self.maxHand = max_num_hands
        self.modecomplex = model_complexity
        self.min_det_con = min_detection_confidence
        self.min_track_con = min_tracking_confidence

        self.mphands = mp.solutions.hands
        self.handdetect = self.mphands.Hands()
        self.draw = mp.solutions.drawing_utils
        self.ID = [4,8,12,16,20]

    #列出21个手指关节位置列表，绘制矩形框
    def findhands(self,img,draw = True):
        RGB_img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)

        # 检测手部，打印位置信息
        self.returns = self.handdetect.process(RGB_img)

        X_list = []
        Y_list = []
        self.lmist = []

        if (self.returns.multi_hand_landmarks):
            for landmarks in self.returns.multi_hand_landmarks:
                # print(landmarks)
                if(draw):
                    self.draw.draw_landmarks(img, landmarks, mp.solutions.hands.HAND_CONNECTIONS)
                    # mp_drawing_styles.get_default_hand_landmarks_style(),
                    # mp_drawing_styles.get_default_hand_connections_style())

                for id, landmark in enumerate(landmarks.landmark):
                    # print(id,landmark)
                    H, W, _ = img.shape
                    x, y = int(landmark.x * W), int(landmark.y * H)
                    X_list.append(x)
                    Y_list.append(y)

                    #print(id, x, y)

                    self.lmist.append([id,x,y])

                x_min, y_min = min(X_list), min(Y_list)
                x_max, y_max = max(X_list), max(Y_list)

                cv2.rectangle(img, (x_min - 20, y_min - 20), (x_max + 20, y_max + 20), (0, 200, 100), 2)

        return img,self.lmist

    #标定指定的手指
    def findfingers(self,img,fingerID):
        x , y = self.lmist[fingerID][1:]
        cv2.circle(img,(x,y),8,(255,0,255),cv2.FILLED)
        return img

    #计算两个手指之间的位置
    def finddistance(self,p1,p2,img,draw=True):
        x1,y1 = self.lmist[p1][1:]
        x2,y2 = self.lmist[p2][1:]

        distance = math.hypot(x1-x2,y1-y2)

        if(draw):
            cv2.line(img,(x1,y1),(x2,y2),(255,0,255),3)


        return distance,img

    #判定哪一个手指伸出来了
    def findfingerUP(self):
        fingers = []
        for id in range(0,5):
            if self.lmist[self.ID[id]][2] < self.lmist[self.ID[id]-2][2]:
                fingers.append(1)
            else:
                fingers.append(0)
        return fingers



def main():
    cap = cv2.VideoCapture(0)
    time1 = 0

    handdetect = HandDetector()

    while True:
        success, img = cap.read()

        #调用封装的函数
        img , position_list = handdetect.findhands(img,draw=False)

        if( len(position_list)!=0 ):
            #print(position_list)

            img = handdetect.findfingers(img,8)
            img = handdetect.findfingers(img,12)

            distance , img = handdetect.finddistance(8,12,img)

            fingers = handdetect.findfingerUP()

            print(fingers)


        # 设置FPS
        time2 = time.time()
        fps = 1 / (time2 - time1)
        time1 = time2
        cv2.putText(img, f'FPS : {int(fps)}', (30, 30), cv2.FONT_HERSHEY_PLAIN, 2, (0, 255, 0), 2)

        cv2.imshow("output", img)
        if cv2.waitKey(1) & 0xff == 27:
            break

    cap.release()

#当模块被直接运行时，以下代码块将被运行，当模块是被导入时，代码块不被运行
if __name__ == '__main__':
    main()